use std::{rc::Rc, cell::RefCell};

use crate::{native, rtda::Frame, instructions::base};

pub fn init() {
    native::register("java/security/AccessController", "doPrivileged", "(Ljava/security/PrivilegedAction;)Ljava/lang/Object;", do_privileged);
	native::register("java/security/AccessController", "doPrivileged", "(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;", do_privileged);
	native::register("java/security/AccessController", "doPrivileged", "(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;", do_privileged);
	native::register("java/security/AccessController", "doPrivileged", "(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;", do_privileged);
	native::register("java/security/AccessController", "getStackAccessControlContext", "()Ljava/security/AccessControlContext;", get_stack_access_control_context);
}

// @CallerSensitive
// public static native <T> T
//     doPrivileged(PrivilegedExceptionAction<T> action)
//     throws PrivilegedActionException;
// (Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;

// @CallerSensitive
// public static native <T> T doPrivileged(PrivilegedAction<T> action);
// (Ljava/security/PrivilegedAction;)Ljava/lang/Object;
fn do_privileged(frame: Rc<RefCell<Frame>>) {
    let vars = frame.borrow().get_local_vars();
    let action = vars.borrow().get_ref(0);

    let stack = frame.borrow().get_operand_stack();
    stack.borrow_mut().push_ref(action.clone());

    let method = unsafe { &*action.unwrap() }.get_class().get_instance_method("run", "()Ljava/lang/Object;"); // TODO
    base::invoke_method(frame, method.unwrap());
}

// private static native AccessControlContext getStackAccessControlContext();
// ()Ljava/security/AccessControlContext;
fn get_stack_access_control_context(frame: Rc<RefCell<Frame>>) {
    // TODO
    frame.borrow().get_operand_stack().borrow_mut().push_ref(None);
}